package captcha

import (
	"bytes"
	"errors"
	"fmt"
	"image"
	"image/color"
	"image/jpeg"
	"io"

	"git.oschina.net/ant180/gotesser/api"
	"git.oschina.net/ant180/gotesser/pub"

	"github.com/xlvector/dlog"
)

type Baixing struct {
	tesser *api.Tesser
}

type ImgCroper interface {
	SubImage(r image.Rectangle) image.Image
}

const (
	BX_PIC_WIDTH  = 50
	BX_PIC_HEIGHT = 50
)

//func NewBaixing(arg interface{}) (*Baixing, error) {
func NewBaixing(arg interface{}) (pub.CaptchaCoder, error) {
	bx := &Baixing{}

	bx.tesser = api.NewTesser("eng", "10")
	if bx.tesser == nil {
		return nil, errors.New("bx: new tessor fail!")
	}

	bx.tesser.SetWhiteList("0123456789")

	return bx, nil
}

func fixResult(buf *bytes.Buffer) string {
	ret := buf.Bytes()
	retLen := len(ret)
	var num [10]byte
	sum := 0

	//fmt.Println("ret: %v", ret)
	for i := 0; i < retLen; i++ {
		sum += int(ret[i])
	}
	//477 = 48 * 9 + 1 + ..... + 9
	if 477 == sum {
		goto lab_return
	}

	for i := 0; i < retLen; i++ {
		c := ret[i] - 48 //'\0' == 48
		if c > 9 || c < 1 {
			continue
			//goto lab_return
		}
		num[c] += 1
	}

	//fmt.Println("num: %v", num)

	for i := 1; i < 10; i++ {
		//修复识别空格
		if 0 == num[i] {
			for j := 0; j < retLen; j++ {
				if ret[j] == ' ' {
					fmt.Println("=======%d %v", j, ret[j])
					ret[j] = byte(48 + i)
					goto lab_return
				}
			}
			//修复识别出两个相同数组
		} else if 2 == num[i] {
			for j := retLen - 1; j >= 0; j-- {
				if ret[j] == byte(48+i) {
					ret[j] = byte(48 + (45 - (sum - 48*9 - i)))
					goto lab_return
				}
			}
		}
	}

lab_return:
	return string(ret)
}

func (p *Baixing) DecodeByReader(r io.Reader) (string, error) {
	img, err := jpeg.Decode(r)
	if err != nil {
		return "", err
	}

	var croper ImgCroper
	switch img.ColorModel() {
	case color.YCbCrModel:
		rimg, ok := img.(*image.YCbCr)
		if ok {
			croper = rimg
		}
	case color.CMYKModel:
		rimg, ok := img.(*image.CMYK)
		if ok {
			croper = rimg
		}
	case color.RGBAModel:
		rimg, ok := img.(*image.RGBA)
		if ok {
			croper = rimg
		}
	case color.NYCbCrAModel:
		rimg, ok := img.(*image.NYCbCrA)
		if ok {
			croper = rimg
		}
	default:
		dlog.Warn("baixing image color model not found")
		return "", errors.New("color model not found")
	}

	if croper != nil {
		picBuff := bytes.NewBuffer(make([]byte, 0, BX_PIC_WIDTH*BX_PIC_HEIGHT*4))
		retBuff := bytes.NewBuffer(make([]byte, 0, 9))
		for i := 0; i < 3; i++ {
			for j := 0; j < 3; j++ {
				picBuff.Reset()
				im := croper.SubImage(image.Rect(i*BX_PIC_WIDTH+2, j*BX_PIC_HEIGHT+2,
					(i+1)*BX_PIC_WIDTH-2, (j+1)*BX_PIC_HEIGHT-2))
				err := jpeg.Encode(picBuff, im, nil)
				if err != nil {
					return "", err
				}
				ret, err := p.tesser.RecognizeMem(picBuff.Bytes())
				if err != nil {
					return "", err
				}
				if len(ret) == 0 {
					ret = " "
				}
				//dlog.Info("%d %d: %s", i, j, ret)
				retBuff.WriteString(ret)
			}
		}

		//return fixResult(retBuff), nil
		return retBuff.String(), nil
	}

	return "", errors.New("image convert fail!")
}

func (p *Baixing) DecodeByMem([]byte) (string, error) {
	return "", nil
}

func (p *Baixing) Close() {
	p.tesser.Close()
}
